import datetime
import time

from coin.exchange.base.kr_rest.rest_client_base import RestUpdate
import coin.exchange.base.kr_rest.public_client_base as pubcb
from coin.exchange.kr_rest.product.product_impl import generate_product_from_str2
import coin.exchange.huobi_futures.kr_rest.native_public_client as npubc
from coin.exchange.huobi_futures.kr_rest.constants import native_subscription_symbol_list
import coin.exchange.huobi_futures.kr_rest.contract_util as contract_util
from coin.exchange.huobi_futures.kr_rest.futures_product import HuobiFuturesProduct
from coin.proto.coin_market_query_pb2 import (
    ProductTicker,
    ExchangeTicker,
    ProductKlineElement,
    ProductKline,
)


class HuobiFuturesFeedParser(object):
  @staticmethod
  def parse_native_ticker(update_msg, product):
    assert update_msg['status'] == "ok"
    ticker = update_msg['tick']
    return ProductTicker(last=float(ticker['close']),
                         high=float(ticker['high']),
                         low=float(ticker['low']),
                         ask=float(ticker['ask'][0]),
                         ask_size=float(ticker['ask'][1]),
                         bid=float(ticker['bid'][0]),
                         bid_size=float(ticker['bid'][1]),
                         exchange_timestamp=int(float(ticker['ts']) * 1e+6),
                         native_symbol=product.native_symbol,
                         symbol=product.symbol)

  @staticmethod
  def parse_exchange_ticker(update_msg):
    product_ticker_list = []
    for ticker in update_msg:
      try:
        native_subscription_symbol = ticker['ch'].split('.')[1]
        base_str, native_subscription_contract = \
          native_subscription_symbol.split('_')
        currency_pair = "%s_%s" % (base_str, 'USD')
        contract_type = contract_util.to_contract_type(native_subscription_contract)
        product = HuobiFuturesProduct.FromCurrencyPairAndContractType(currency_pair, contract_type)
        product_ticker = HuobiFuturesFeedParser.parse_native_ticker(ticker, product)
        product_ticker_list.append(product_ticker)
      except Exception as e:
        print(ticker, type(e), e)
        continue
    assert len(product_ticker_list) > 0
    return ExchangeTicker(exchange="Huobi", market_type='Futures', each_ticker=product_ticker_list)

  @staticmethod
  def parse_native_kline(update_msg, product, kline_period, start_time, end_time):
    """Sample kline response:
        {
          "ch": "market.BTC_CQ.kline.1min",
          "data": [
            {
              "vol": 2446,
              "close": 5000,
              "count": 2446,
              "high": 5000,
              "id": 1529898120,
              "low": 5000,
              "open": 5000,
              "amount": 48.92
             },
            {
              "vol": 0,
              "close": 5000,
              "count": 0,
              "high": 5000,
              "id": 1529898780,
              "low": 5000,
              "open": 5000,
              "amount": 0
             }
           ],
          "status": "ok",
          "ts": 1529908345313
        }
    """
    klines = update_msg['data']
    kline_group = []
    end_time = datetime.datetime.utcfromtimestamp(end_time.timestamp())
    for kline in klines:
      kline_timestamp = kline['id']
      if kline_timestamp >= start_time.timestamp() and \
         kline_timestamp < end_time.timestamp():
        product_kline = ProductKlineElement(kline_timestamp=int(kline['id'] * 1e+9),
                                            open=float(kline['open']),
                                            high=float(kline['high']),
                                            low=float(kline['low']),
                                            close=float(kline['close']),
                                            volume=float(kline['vol']) / 2,
                                            turnover=float(kline['amount']) / 2)
        kline_group.append(product_kline)
    assert len(kline_group) > 0
    return ProductKline(
        symbol=product.symbol,
        native_symbol=product.native_symbol,
        exchange='Huobi',
        market_type='Futures',
        kline_period=kline_period,
        klines=kline_group,
    )


class HuobiFuturesPublicClient(pubcb.PublicClientBase):
  def __init__(self, timeout=1):
    self.npubc = npubc.HuobiFuturesNativePublicClient(timeout=timeout)

  def query_ticker_impl(self, product):
    native_subscription_symbol = product.native_subscription_symbol
    update = self.npubc.get_ticker(native_subscription_symbol)
    update.msg = HuobiFuturesFeedParser.parse_native_ticker(update.msg, product)
    return update

  def query_exchange_ticker_impl(self):
    reqtime = time.time()
    ticker_list = []
    for native_subscription_symbol in native_subscription_symbol_list:
      ticker_list.append(self.npubc.get_ticker(native_subscription_symbol).msg)
    restime = time.time()
    update = RestUpdate(reqtime, restime, ticker_list)
    update.msg = HuobiFuturesFeedParser.parse_exchange_ticker(update.msg)
    return update

  def query_history_kline_impl(self, product, kline_period, start_time, end_time):
    size = 2000
    native_subscription_symbol = product.native_subscription_symbol
    update = self.npubc.get_history_kline(native_subscription_symbol, kline_period, size)
    update.msg = HuobiFuturesFeedParser.parse_native_kline(update.msg,
                                                           product,
                                                           kline_period,
                                                           start_time,
                                                           end_time)
    return update

  def query_level_book_impl(self, product):
    raise NotImplementedError()
